home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
ps.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
48KB
|
1,779 lines
/*
* $Id: ps.c,v 0.91 1994/02/23 02:26:57 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* PostScript support:
*
* Rasterization is done via psrender or ghostscript at configurable
* resolutions. In case of multi-page EPS files, multi-image handler
* is called to allow random access to each page.
*
* On output, bit produces a parameterized color EPS file unless of
* course the input image is grayscale. Currently, no consideration is
* given to text and sgfs as far as checking if their are off page although
* their contribution to the overall size and bounding box is considered.
* Maybe a flag to request to center the whole bounding box rather than
* centering the raster only as current implementation does.
*
* Warning: If PCBITS is not 8, need to renormalize the primary color
* before doing any thing. This is unchecked.
*
* BUGS: always generates 8bits grapscale even if B&W images
*/
#ifndef NO_PS
#if !defined(lint) && defined(F_ID)
char *id_ps = "$Id: ps.c,v 0.91 1994/02/23 02:26:57 zhao Pre-Release $";
#endif
#include "bit.h"
#include "extern.h"
#include "tsdef.h"
#include <math.h> /* for log10 */
/*******************************************************************
* PostScript loading is supported either thru psrender or ghostscript
****************************************************************{**/
/********************************************************************
* resolutions to use when converting PS to raster image.
* Gloabl variable ps_res_index is initialized to zero and used
* as an index into ps_res table.
* gps_res_string returns the string representtion of resolutions
********************************************************************/
static int ps_res[] =
{
96, 150, 300, 400, 35, 72
};
const char *
gps_res_string(void)
{
return "96dpi|150dpi|300dpi|400dpi|35dpi|72dpi";
}
int
PS_desc(IPTR im)
{
im->w = im->h = 1;
im->type = T_RGBA;
return 0;
}
/******************************************************************
* Read a PS file via either ghostscript or psrender
******************************************************************/
#define GS_DEVICE "ppmraw"
#define GS_OPT "-q -DNOPAUSE"
static int npage, cur_page; /* no. of pages in EPS file */
static int isgs = 1; /* ghostscript ok */
static char psprefix[MAXDLEN]; /* prefix for converted files */
static char pspat[MAXDLEN]; /* psprefix + * */
static FL_FORM *multipage;
static void create_form_multipage(void);
/**************************************************************
* Load rasterized page, cur_page.
* Page is stored in a file whose name is generated on the fly
* depending which/what interpreter is used.
* Return -1 for failure
**************************************************************/
static int
load_page(IPTR im)
{
static char fname[1024];
int badload;
if (isgs)
sprintf(fname, "%s%d", psprefix, cur_page);
else
sprintf(fname, "%s%0*d.rgb", psprefix,
(int) (log10(npage) + 1.1), cur_page);
M_info("PS_Load", "trying %s", fname);
/* block paging request while loading */
fl_deactivate_form(multipage);
close_image(im);
badload = !(im->fp = fopen(get_TMPfile(fname), "r")) ||
(PNM_desc(im) < 0 || img_get_rastermem(im) < 0);
badload = badload ||
(((IS_CI(im) ? PBM_load : PPM_load) (im) >= 0) ? 0 : -1);
M_info("PS_load", "Loading %sOK", badload ? "Not " : "");
/* check if black & white */
if (!badload && IS_CI(im) && preserve_wm_colors)
img_preserve_wm_colors(im);
M_info("PS_load", "Preserving OK");
fl_activate_form(multipage);
/*
* for multi-page EPS file, multi handler will clean after itself. remove
* file only if single page PS file
*/
if (npage == 1)
remove(get_TMPfile(fname));
return badload ? -1 : 0;
}
/*****************************************************************
* Call external interpretor to render the (e)PS files. All rendered
* pages are written to disk. This routine only load the first page
******************************************************************/
int
PS_load(IPTR im)
{
char shcmd[1024];
int np, psres = ps_res[ps_res_index], status;
static int ui;
Dirlist *dl, *dls;
/* get the tail of filename */
strcpy(pspat, file_tail(im->ifile));
/* and generate a uniq pattern out of it for output files */
sprintf(psprefix, "%s_%d%s", pspat, ui++, "_eps");
strcat(strcpy(pspat, psprefix), "*");
M_info("PS_load", "psprefix=%s pspat=%s", psprefix, pspat);
/* always try gs first: smarter than psrender */
show_busy("Reading PS ...");
sprintf(shcmd, "gs -sDEVICE=%s %s -r%d -sOutputFile=%s%%d -- %s",
GS_DEVICE, GS_OPT, psres, get_TMPfile(psprefix), im->ifile);
M_info("PSLoad", "%s", shcmd);
isgs = 1;
if ((status = system(shcmd)))
{
isgs = 0;
M_info("PS_load", "gs failed with error code %d", status);
sprintf(shcmd, "psrender -d image -r %d -o %s %s",
psres, get_TMPfile(psprefix), im->ifile);
M_info("PSLoad", "%s", shcmd);
status = system(shcmd);
}
if (status)
{
Bark("PS_load", "Both gs and psrender failed");
return -1;
}
create_form_multipage();
/* succesful: see how many pages we've got */
if (!(dl = get_dir_list(tmppath, pspat, &np, 1)))
return -1;
M_info("PS_load", "total of %d files", np);
/* dirlist always contain dirs, remove it from dirlist. */
for (dls = dl + np; dl < dls; dl++)
{
if (dl->type == FT_DIR)
--np;
}
/* this is the true no. of pages */
if ((npage = np) <= 0)
return -1;
M_info("PS_load", "total of %d pages", npage);
cur_page = 1;
/* if more than one page, say so to the driver */
im->more = npage > 1;
status = load_page(im);
M_info("LoadPage", "status=%d", status);
/* load the first page and return */
return status >= 0 ? 0 : -1;
}
/**** Handle multi-page EPS files **/
static FL_OBJECT *flpagecnt;
static void
show_page_no(IPTR im)
{
char ha[100];
sprintf(ha, "EPS Page %d of %d", cur_page, npage);
set_iformat_info(im, ha);
update_image_info(im);
}
int
PS_next(IPTR im, int n)
{
short val;
int oreport = report_level;
report_level = 0; /* supress progress report */
create_form_multipage();
show_page_no(im);
fl_set_slider_bounds(flpagecnt, 1, npage);
fl_set_slider_value(flpagecnt, 1);
bit_show_form(multipage, FL_PLACE_MOUSE, 0, "EPS_PAGE");
while (bit_qread(&val) != F1KEY || !val)
;
bit_hide_form(multipage);
report_level = oreport;
/* clean up all files */
rm_all_files(tmppath, pspat);
im->more = 0;
return 0;
}
/***** Display a particular page, cur_page ****/
static void
show_page(IPTR im)
{
show_page_no(im);
/* load & display */
im->ok = load_page(im) >= 0;
im->io->display(im, display_style, 0);
}
/* ARGSUSED */
static void
ps_random_page(FL_OBJECT * ob, long q)
{
int n = (fl_get_slider_value(ob) + 0.1);
if (cur_page != n)
{
cur_page = n;
show_page(imgptr);
}
}
/* ARGSUSED */
static void
ps_next_prev_page(FL_OBJECT * ob, long q)
{
int n = cur_page + q;
n = (n < 1 ? 1 : (n > npage ? npage : n));
if (cur_page != n)
{
cur_page = n;
fl_set_slider_value(flpagecnt, cur_page);
show_page(imgptr);
}
}
/* ARGSUSED */
static void
ps_page_done(FL_OBJECT * ob, long q)
{
fl_qenter(F1KEY, 100);
}
static void
create_form_multipage(void)
{
FL_OBJECT *obj;
if (multipage)
return;
multipage = fl_bgn_form(FL_NO_BOX, 200.0, 205.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 200.0, 205.0, "");
fl_set_object_color(obj, 12, 47);
obj = fl_add_box(FL_DOWN_BOX, 10.0, 10.0, 180.0, 185.0, "");
fl_set_object_color(obj, 9, 47);
obj = fl_add_text(FL_NT, 30.0, 160.0, 140.0, 25.0, "MultiPage Image");
fl_set_object_lcol(obj, 4);
fl_set_object_align(obj, FL_ALIGN_CENTER);
obj = fl_add_button(FL_NB, 30.0, 70.0, 70.0, 25.0, "PrevPage");
fl_set_object_color(obj, 47, 9);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, ps_next_prev_page, -1);
obj = fl_add_button(FL_NB, 100.0, 70.0, 70.0, 25.0, "NextPage");
fl_set_object_color(obj, 47, 9);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, ps_next_prev_page, 1);
flpagecnt = obj = fl_add_valslider(FL_HNS, 20.0, 110.0, 160.0, 25.0,
"Current EPS Page");
fl_set_object_color(obj, 9, 1);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_TOP);
fl_set_slider_return(obj, 0);
fl_set_slider_precision(obj, 0);
fl_set_slider_step(obj, 1);
fl_set_call_back(obj, ps_random_page, 0);
obj = fl_add_button(FL_NB, 115.0, 20.0, 60.0, 25.0, "Done");
fl_set_object_color(obj, 47, 9);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, ps_page_done, 0);
fl_end_form();
}
/*****************************************************************
* END of reading *
**************************************************************}**/
/*****************************************************************
* EPS output
*****************************************************************/
/******* Defines and limits. Some modifiable at run time *****/
#define PS_LINE 36 /* 72 characters per line */
#define PRINTER_DPI 300 /* default printer res. */
#define PG_WIDTH 8.5 /* page width in inches */
#define PG_HEIGHT 11.0 /* page height in inches */
#define MARGIN 0.4 /* margin, about 1cm */
#define MINTEXTSIZE 4.0 /* minimum font size */
/************ Output related variables *********************/
static float s2p; /* factor from screen size to print size */
static float gxscale = 1.0; /* X scale, further modified by s2p */
static float gyscale = 1.0; /* Y scale, further modified by s2p */
static int autoscale = 1; /* true to auto scale(down) */
static int matchscreen = 1; /* if make hardcopy same size as on scrn */
static int landscape; /* the actual placement */
static int textscale; /* if scale applies to text */
static float xo, yo; /* offset into page */
static float page_h = PG_HEIGHT;/* Default paper width */
static float page_w = PG_WIDTH; /* Default paper height */
static float hm = MARGIN; /* horizotal margin */
static float vm = MARGIN; /* vertical margin */
static int pdpi = PRINTER_DPI; /* printer resolution */
static int screen_dpi; /* screen resolution */
static int misct, miscl, miscb, miscr; /* text and sgf sizes */
static int psnewcolor, psnewfont; /* initialization flag */
static FL_FORM *fmpsinit;
static void get_summary(void);
extern void get_misc_size(IPTR, int *, int *, int *, int *);
static void create_form_psinit(void);
/********************************************************
* Generate current output parameters in string format
********************************************************/
/* placement: -1: auto 0: portrait 1: landscape */
static int place = -1;
static const char *rplace[] =
{
"Autofit", "Portrait", "Landscape"
};
/* ARGSUSED */
const char *
PS_wdefault(const IPTR im)
{
static char qtmp[100];
const char *p = rplace[place + 1];
if (autoscale)
sprintf(qtmp, "Autoscale %s", p);
else
sprintf(qtmp, "Xs=%g Ys=%g %s", gxscale, gyscale, p);
return qtmp;
}
/*************************************************************
* Get options interactively. Called by driver
***************************************************************/
int
PSdump_init(IPTR im)
{
create_form_psinit();
screen_dpi = get_scr_dpi();
get_misc_size(im, &misct, &miscl, &miscb, &miscr);
get_summary();
fl_deactivate_all_forms();
bit_show_form(fmpsinit, FL_PLACE_MOUSE, 0, "PSoption");
/* will be reactivated by cancel or ok */
return 0;
}
static void
PS_push(FILE * fp)
{
fputs("gsave\n", fp);
}
static void
PS_pop(FILE * fp)
{
fputs("grestore\n", fp);
}
static void
PS_move(FILE * fp, int x, int y)
{
fprintf(fp, "%d %d moveto\n", x, y);
}
static char pscmd[100];
/********************************************************************
* Write conforming PS header and comments. default user coordinates
* system is used throughout, whose units incidently are almost the same
* as a pixel-pixel distance on screen, and we can use the pixel as the
* unit and get a hardcopy that is approximately the same as they appear
* on screen
***********************************************************************/
/* special characters in PS */
#define PS_SPC(c) ( (c)=='(' || (c)==')' || (c)=='[' || (c)==']' || \
(c)=='<' || (c)=='>' || (c)=='%' || (c)=='\\' || (c)=='#')
/* Maximum number of supported SGF's */
#define MAXOBJDEFS 20
/*************************************************************
* Find the optimum scale factors such that the scaled image
* (just) fit the printed page (minus the margins)
*************************************************************/
static int
auto_scale(float pgw, float pgh, float w, float h)
{
float rescalex, rescaley;
int i = 0;
if ((!landscape && (pgw < w || pgh < h)) ||
(landscape && (pgw < h || pgh < w)))
{
if (!landscape)
{
rescalex = (pgw - 2.0) / w;
rescaley = (pgh - 2.0) / h;
}
else
{
rescalex = (pgw - 2.0) / h;
rescaley = (pgh - 2.0) / w;
}
i = (100.0 * Min(rescalex, rescaley));
}
return i;
}
/*************************************************************
* Find the optimum orientation
**************************************************************/
static void
auto_fit(float pgw, float pgh, float w, float h)
{
int plm, pbm, llm, lbm;
plm = (pgw - w) / 2;
pbm = (pgh - h) / 2;
llm = (pgw - h) / 2;
lbm = (pgh - w) / 2;
landscape = (Abs(lbm - llm) < Abs(pbm - plm));
}
/******************************************************************
* check if scaling is needed to fit the page. All units are
* in Ps units, i.e., 72 units per inch.
******************************************************************/
static void
check_size(int *ww, int *hh, int fit)
{
float pgw = page_w - 2.0 * hm; /* writable area */
float pgh = page_h - 2.0 * vm; /* writable area */
float rescale;
int w = *ww, h = *hh;
float hhm, vvm;
int i, n;
pgw *= 72.0;
pgh *= 72.0;
hhm = hm * 72.0;
vvm = vm * 72.0;
if (autoscale)
gxscale = gyscale = 1.0;
s2p = matchscreen ? (72.0 / screen_dpi) : 1.0;
w *= gxscale * s2p;
h *= gyscale * s2p;
/* make sure each unit has integral no. of printer dots */
if ((n = (pdpi / 72.0 + 0.5)) < 1)
n = 1;
w = (w * 72.0 / pdpi) * n;
h = (h * 72.0 / pdpi) * n;
/* file maybe extremely small or printer very expensive! */
if (w < 1 || h < 1)
{
w = (w * 72.0 * n / pdpi);
h = (h * 72.0 * n / pdpi);
}
/* true size should be scaled to match the screen size */
/* find the best placement if auto */
if ((landscape = place) == -1)
auto_fit(pgw, pgh, w, h);
/* check if image will fit on a page only if requested */
if (fit || autoscale)
{
i = auto_scale(pgw, pgh, w, h);
if ((rescale = 0.01 * i) < 0.005)
rescale = 1.0;
if (i >= 2 && !autoscale)
{
sprintf(pscmd, "rescale (by %.2f) ?", rescale);
if (!yes_no("Warning", "Image too large to fit", pscmd, 0))
rescale = 1.0;
}
gxscale *= rescale;
gyscale *= rescale;
w *= rescale;
h *= rescale;
}
/*
* get the origin of the system, for BoundingBox only. Actual PS file
* will do this calculation on the fly for possible further editing.
*/
xo = hhm + (pgw - (landscape ? h : w)) * 0.5;
yo = vvm + (pgh - (landscape ? w : h)) * 0.5;
xo -= (landscape ? miscb : miscl) * gxscale * s2p;
yo -= (landscape ? miscl : miscb) * gyscale * s2p;
*ww = w;
*hh = h;
}
/**************************************************************
* actual header emitting routine
****************************************************************/
static void PS_text_init(FILE *);
static void PS_sgf_init(FILE *);
static void
PS_header(IPTR im)
{
FILE *fp = im->fp;
int rgb = IS_RGBA(im);
int w = im->w, h = im->h;
char *psc;
const char *bdef = "bind def";
check_size(&w, &h, 1);
w += (miscr + miscl) * gxscale * s2p;
h += (misct + miscb) * gyscale * s2p;
/* Write a conforming header */
fputs("%!PS-Adobe-3.0 EPSF-2.0\n", fp);
fprintf(fp, "%%%%Creator: %s (C) 1993, T.C. Zhao\n", rm_rcs_kw(sver));
fprintf(fp, "%%%%Title: %s(%g X %g)\n",
im->ifile, gxscale * s2p, gyscale * s2p);
fprintf(fp, "%%%%CreateDate: %s\n", current_ascii_date());
/* we enlarge the bounding box by 2 units for possible thick lines */
fprintf(fp, "%%%%BoundingBox: %d %d %d %d\n",
(int) (xo - 1), (int) (yo - 1),
(int) (xo + w + 1.5), (int) (yo + h + 1.5));
fprintf(fp, "%%%%Pages: 1\n");
if (number_of_text() > 0)
{
fprintf(fp, "%%%%DocumentFonts: %s\n", get_text_fontname(0));
}
fputs("%%EndComments\n", fp);
/* Prolog. Basic defines. */
fputs("/inch { 72 mul } def \n", fp);
fputs("\n% Beginning of modifiable parameters\n", fp);
fprintf(fp, "/pagew {%.2g inch} %s \t%% page width\n", page_w, bdef);
fprintf(fp, "/pageh {%.2g inch} %s \t%% page height\n", page_h, bdef);
fprintf(fp, "/lm {%.2g inch} %s \t%% Left margin\n", hm, bdef);
fprintf(fp, "/bm {%.2g inch} %s \t%% Bottom margin\n", vm, bdef);
fprintf(fp, "/xscale %g def \t%% global xscale\n", s2p * gxscale);
fprintf(fp, "/yscale %g def \t%% global yscale\n", s2p * gxscale);
fputs("% End of modifiable parameters\n\n", fp);
fprintf(fp, "/pw {pagew lm 2 mul sub} %s \t%% writable width\n", bdef);
fprintf(fp, "/ph {pageh bm 2 mul sub} %s \t%% writable height\n", bdef);
/*
* instead of emitting numbers, the actual calculation is output so that
* both scale and margin can be adjusted in PS
*/
fprintf(fp, "/xo pw xscale div %d sub 2 div def \t%% xo\n",
landscape ? im->h : im->w);
fprintf(fp, "/yo ph yscale div %d sub 2 div def \t%% yo\n",
landscape ? im->w : im->h);
PS_text_init(fp);
PS_sgf_init(fp);
sprintf(pscmd, "StartRasterOf%s", im->ifile);
/* replace special characters with $ */
psc = pscmd;
while (*psc++)
if (PS_SPC(*psc))
*psc = '$';
/*
* there is a bug in PSVIEW(IRIX 3.3) that the pagematrix is not honored.
* Have to code the default, i.e., from ToptoBottom for preview
*/
if (!rgb)
{
fprintf(fp, "/graystring %d string def\n", im->w);
fprintf(fp, "/%s\n", pscmd);
fprintf(fp, " {%d %d %d [ %d 0 0 -%d 0 %d]\n",
im->w, im->h, (int) PCBITS, im->w, im->h, im->h);
fputs(" {currentfile graystring readhexstring pop}\n", fp);
fputs(" image\n} bind def\n", fp);
}
else
{
fprintf(fp, "/redstring %d string def\n", im->w);
fprintf(fp, "/grnstring %d string def\n", im->w);
fprintf(fp, "/blustring %d string def\n", im->w);
fprintf(fp, "/%s\n", pscmd);
fprintf(fp, " {%d %d %d [ %d 0 0 -%d 0 %d]\n",
im->w, im->h, (int) PCBITS, im->w, im->h, im->h);
fputs(" {currentfile redstring readhexstring pop}\n", fp);
fputs(" {currentfile grnstring readhexstring pop}\n", fp);
fputs(" {currentfile blustring readhexstring pop}\n", fp);
fputs(" true 3 colorimage\n} bind def\n", fp);
}
fputs("%%EndProlog\n%%Page: 1 1\n", fp);
/* honor the margin request */
PS_push(fp);
fputs("lm bm translate % Margins\n", fp);
}
static void
PS_trailer(FILE * fp)
{
PS_pop(fp);
fputs("showpage\n", fp);
fputs("%%Trailer\n", fp);
}
static void
PS_rotate(IPTR im)
{
if (landscape)
{
fprintf(im->fp, "%d %d translate\n", im->h, 0);
fputs(" 90 rotate\n", im->fp);
}
}
static void
PS_translate(IPTR im)
{
fputs("xo yo translate\n", im->fp);
}
static void
PS_scale(IPTR im)
{
fputs("xscale yscale scale\n", im->fp);
}
static void
PS_ras_scale(IPTR im)
{
fprintf(im->fp, " %d %d scale\n", im->w, im->h);
}
/* scale and rotate */
static void
PS_map(IPTR im)
{
PS_scale(im);
PS_translate(im);
PS_rotate(im);
}
/********************************************************************
* Text related output routines: the source of text attributes
* are defined by text routines in deferred mode.
****************************************************************{*/
/*************************************************************
* Switch to ISOLatin1 to get some of the special characters.
* If the printer is level 1 only, switching code has not
* effect.
*************************************************************/
static void
switch_to_ISOLatin1(FILE * fp)
{
/***** usage: newfontname oldfontname SwitchISO ******/
fputs("\n% Switch to ISOLatin1 to get special characters\n", fp);
fputs("/languagelevel where\n", fp);
fputs(" {pop languagelevel} {1} ifelse\n", fp);
fputs(" 2 lt {/BitEncoding /StandardEncoding load def}\n", fp);
fputs(" {/BitEncoding /ISOLatin1Encoding load def}\n", fp);
fputs(" ifelse\n", fp);
fputs("/SwitchToISO {\n", fp);
fputs(" findfont dup length\n dict begin {1 index /FID ne {def} "
"{pop pop} ifelse} forall\n", fp);
fputs(" /Encoding BitEncoding def ", fp);
fputs(" currentdict end\n definefont pop\n} bind def\n", fp);
}
/****************************************************************
* Define commands to handle justification of a string placement
*****************************************************************/
struct tplace
{
const char *pname; /* placement name */
const char *how; /* how to do it(PS code) */
};
static const struct tplace pt[] =
{
{"Lshow", "show"},
{"Cshow", "dup stringwidth pop -2 div 0 rmoveto show"},
{"Rshow", "dup stringwidth pop neg 0 rmoveto show"}
};
static void
PS_text_init(FILE * fp)
{
if (number_of_text() <= 0)
return;
fputs("% Specific to text\n", fp);
fprintf(fp, "/%s { %s } bind def\n", pt[0].pname, pt[0].how);
fprintf(fp, "/%s { %s } bind def\n", pt[1].pname, pt[1].how);
fprintf(fp, "/%s { %s } bind def\n", pt[2].pname, pt[2].how);
fputs("/SetFont {findfont exch scalefont setfont} bind def\n", fp);
if (!textscale)
fprintf(fp, "/fixed {xscale yscale add 2 div div} bind def\n");
switch_to_ISOLatin1(fp);
}
/**************************************************************
* scale a font. Assuming fname is indeed a pointer to constant
***************************************************************/
#define MAXCFONT 60
static void
PS_text_scale(FILE * fp, const char *fname, float size)
{
static const char *fontcache[MAXCFONT], *cfont;
const char *suffix = "ISOLatin1";
static float csize;
int i;
float ssize;
if (psnewfont)
{ /* should be turned on by ps_dump */
csize = -1;
cfont = 0;
psnewfont = 0;
for (i = MAXCFONT; --i >= 0;)
fontcache[i] = 0;
}
/* change font only if different from current */
if (Abs(size - csize) > 0.2 || cfont != fname)
{
int old;
/* define new font only once */
for (i = old = 0; !old && fontcache[i] && i < MAXCFONT; i++)
old = fname == fontcache[i];
if (!old)
{ /* virgin */
fprintf(fp, "/%s%s /%s SwitchToISO\n", fname, suffix, fname);
i = -1;
while (fontcache[++i])
;
fontcache[i] = fname;
}
if (textscale)
{
ssize = size;
/* make sure scaled size is no less than MINTEXSIZE */
if ((ssize * 0.5 * s2p * (gxscale + gyscale)) < MINTEXTSIZE)
ssize = MINTEXTSIZE * 2.0 / (s2p * (gxscale + gyscale));
fprintf(fp, "%.2f /%s%s SetFont\n", ssize, fname, suffix);
}
else
{ /* do not want to scale text */
fprintf(fp, "%.2f fixed /%s%s SetFont\n", size, fname,
strcmp(fname, "Symbol") ? suffix : "");
}
cfont = fname;
csize = size;
}
}
static void
PS_color(FILE * fp, int r, int g, int b, int gray)
{
static int cr, cg, cb;
if (psnewcolor)
{
cr = cg = cb = -1;
psnewcolor = 0;
}
if ((cr - r) || (cg - g) || (cb - b))
{ /* different */
if (gray)
fprintf(fp, "%.2f setgray ", C2NC(rgb2gray(r, g, b)));
else
fprintf(fp, "%.2f %.2f %.2f setrgbcolor ",
C2NC(r), C2NC(g), C2NC(b));
cr = r;
cg = g;
cb = b;
}
}
/*********************************************************************
* output the string. Need to take care of unprintable and
* special characters
*******************************************************************/
static void
PS_print_string(FILE * fp, const char *str)
{
register const unsigned char *p = (const unsigned char *) str;
while (p && *p)
{
if (*p < 32 || *p > 123)
{
fprintf(fp, "\\%o", *p);
}
else
{
if (PS_SPC(*p))
putc('\\', fp);
putc(*p, fp);
}
p++;
}
}
/* given a font and a string, get the length */
const char *pslen = "/strlength strlength (%s) stringwidth pop add def\n";
static void
PS_out_text(FILE * fp, int n)
{
register const char *p;
int pl = get_text_placement(n);
Line *line = get_text_line(n);
int nt = line->ntokens;
const char *cfont = get_text_fontname(n);
float csize = get_text_fontsize(n);
p = get_text_string(n);
fprintf(fp, "%% str%d %s\n", n, p);
if (nt == 1)
{ /* not font switch */
PS_text_scale(fp, cfont, csize);
putc('(', fp);
PS_print_string(fp, p);
fprintf(fp, ") %s\n", pt[pl].pname);
}
else
{ /* need font switching */
Token *t, *ts;
if (pl == TCENTER || pl == TRIGHT)
{
fputs("/strlength 0 def\n", fp);
/* get the string length */
for (t = line->token, ts = t + nt; t < ts; t++)
{
PS_text_scale(fp, t->math ? "Symbol" : cfont, t->size);
fprintf(fp, pslen, t->str);
}
/* string length is now in strlength */
if (pl == TCENTER)
fputs("strlength -2 div 0 rmoveto\n", fp);
else
fputs("strlength neg 0 rmoveto\n", fp);
}
/* now output the string */
for (t = line->token, ts = t + nt; t < ts; t++)
{
PS_text_scale(fp, t->math ? "Symbol" : cfont, t->size);
putc('(', fp); /* ) */
PS_print_string(fp, t->str);
/* ( */
fprintf(fp, ") show\n");
}
}
}
/*********************************************************************
* Routine invoked to handle all text
**********************************************************************/
static void
PS_text(IPTR im)
{
int n, r, g, b;
int px, py, i;
float trot;
FILE *fp = im->fp;
if ((n = number_of_text()) <= 0)
return;
fputs("\n% Text. All distance are from ll corner\n", fp);
for (i = 0; i < n; i++)
{
get_text_color(i, &r, &g, &b);
PS_color(fp, r, g, b, IS_GRAY(im));
get_text_location(i, &px, &py);
PS_move(fp, px, py);
if ((trot = get_text_rotation(i)) > 0.1)
{
PS_push(fp);
fprintf(fp, "%.1f rotate\n", trot);
PS_out_text(fp, i);
PS_pop(fp);
}
else
PS_out_text(fp, i);
}
}
/********* END of text routines *******************}*********/
/************************************************************************
* simple geometric figure drawings. could've written a PS routine that
* takes (x,y), (w,h), t as parameters and produces the figure, but this
* way is faster. The only problem is that when the scale in x&y direction
* is very different, the line thickness would appear uneven .... could be
* corrected by using more than one strokes .....
*
* Basic commands:
* M -- moveto LT -- lineto L -- line from (xi,yi) to (xf,yf)
*
* Make sure number of objects not exceed MAXOBJDEFS. All PS objects have
* a size of 2
***********************************************************************/
const char ps_plus[] = "-1 0 1 0 L 0 -1 0 1 L";
const char ps_rect[] = "-1 1 -1 -1 L 1 1 LT 1 -1 LT C";
const char ps_tri[] = " -1 -1 0 1 L 1 -1 LT C";
const char ps_circ[] = " 0 0 1 0 360 arc";
const char ps_hdist[] = "-1 0 1 0 L 1 0.25 1 -0.25 L -1 0.25 -1 -0.25 L";
const char ps_line[] = "0 1 0 -1 L";
const char ps_arrow[] = "0.7 0 -1 0 L dup setlinewidth stroke \n"
"0.7 0 M 0.7 -0.10 LT 1 0 LT 0.7 0.10 LT 0.7 0 LT C";
const char ps_star[] =
"0 1 0.2245 0.309 L -0.2245 0.309 LT -0.9511 0.309 LT\n"
"-0.3633 -0.118 LT -0.5878 -0.809 LT 0 -0.382 LT 0.5878 -0.809 LT\n"
"0.3633 -0.1180 LT 0.9511 0.309 LT 0.2245 0.309 LT C ";
static const char *pspaint[] =
{
"stroke", "fill"
};
static void
PS_sgf_init(FILE * fp)
{
const char *sgfi = "sgfi";
const char *name;
const char *nbuff[MAXOBJDEFS];
int i, n, s, j, k = 0;
/* sgf definitions */
if ((n = number_of_sgf()) <= 0)
return;
for (j = MAXOBJDEFS; --j >= 0;)
nbuff[j] = 0;
fputs("% SGFs. All takes t, w, h,angle, xo, yo\n", fp);
fputs("/M {moveto} bind def /LT {lineto} bind def\n", fp);
fputs("/L {M LT} bind def /C {closepath} bind def\n", fp);
fputs("/Bgnsgf {gsave} def /Endsgf {grestore} def\n", fp);
fprintf(fp, "/%s {newpath translate rotate scale} bind def\n", sgfi);
/* define all the stuff used. */
for (i = 0; i < n; i++)
{
name = sgf_name(i);
for (j = s = 0; !s && j < MAXOBJDEFS; j++)
s = (name == nbuff[j]);
if (!s)
{
nbuff[k++] = name;
fprintf(fp, "/%s {%s %s setlinewidth} def\n",
sgf_name(i), sgfi, sgf_psdraw(i));
}
}
}
/* take care of simple geometric figures */
static void
PS_sgf(IPTR im)
{
int i, n;
int x, y, w, h, t, f, r, g, b;
int angle;
FILE *fp = im->fp;
if ((n = number_of_sgf()) <= 0)
return;
fputs("\n% sgfs. Stack: t x y w h. Distance are from LL corner\n", fp);
for (i = 0; i < n; i++)
{
get_sgf_info(i, &x, &y, &w, &h, &t, &f, &angle);
get_sgf_color(i, &r, &g, &b);
PS_color(fp, r, g, b, IS_GRAY(im));
/*
* all drawing routines have a size of 2 and thickness is scaled by
* w or h, an average is taken
*/
fprintf(fp, "Bgnsgf %.3g %.3g %g %d %d %d %s ",
(float) 2.0 * t / (w + h), 0.5 * w, 0.5 * h, angle,
x, y, sgf_name(i));
/* color and stroke */
fprintf(fp, "%s Endsgf\n", pspaint[f]);
}
return;
}
static int to_ps(IPTR);
static int to_cps(IPTR);
/**********************************************************************
* write ps files. apply all transformation at the beginning of writing,
* and * since all text and sgfs are relative to image, this reduces
* ps activities
***********************************************************************/
int
PS_dump(IPTR im)
{
int status;
psnewcolor = psnewfont = 1; /* signal cache re-init */
screen_dpi = get_scr_dpi();
get_misc_size(im, &misct, &miscl, &miscb, &miscr);
PS_header(im);
PS_push(im->fp); /* save old state */
/*
* apply current transformation, particularly, the lower left corner of
* the image will be the origin
*/
PS_map(im);
/* write out the raster */
status = (IS_RGBA(im) ? to_cps : to_ps) (im);
/* do text and sgfs */
PS_text(im);
PS_sgf(im);
PS_pop(im->fp); /* restore old state */
PS_trailer(im->fp);
remove_progress_report();
return status;
}
#define OUTPIXEL(c) \
do { \
putc(hexdigits[(c) >> 4],fp); \
putc(hexdigits[(c) & 15],fp); \
} while (ZERO)
static int
to_ps(IPTR im)
{
register rgba_t *rgba, *rs;
register int k, g, j;
long rlines;
FILE *fp = im->fp;
PS_push(im->fp); /* save old state */
PS_ras_scale(im);
/* command that starts the image stream */
fputs("% raster starts here\n", fp);
fprintf(fp, "%s\n", pscmd);
rlines = progress_report(IS_BW(im) ?
"Writing B&W PS ..." : "Write GrayPS ...", im->h);
for (j = 0, k = 1; j < im->h; j++)
{
rgba = ((rgba_t **) im->mraster)[im->h - 1 - j];
for (rs = rgba + im->w; rgba < rs; rgba++, k++)
{
g = (*rgba & (PCMAX - 1));
OUTPIXEL(g);
if ((k % PS_LINE) == 0)
putc('\n', fp);
}
REPORT(j, rlines);
}
putc('\n', im->fp);
PS_pop(im->fp); /* restore old state */
return 0;
}
/************** Color postscript *****************************/
static int
to_cps(IPTR im)
{
int j, k;
long rlines;
FILE *fp = im->fp;
register pc_t *pc, *ss;
/* get the rgb matrix before we do anything */
if (img_get_rgb(im) < 0)
return -1;
PS_push(im->fp); /* save old state */
PS_ras_scale(im);
/* command that starts the image stream */
fputs("% raster starts here\n", fp);
fprintf(fp, "%s\n", pscmd);
rlines = progress_report("Write ColorPS ...", im->h);
/* always code the default */
for (j = im->h, k = 1; --j >= 0;)
{
for (pc = get_RM(im)[j], ss = pc + im->w; pc < ss; pc++, k++)
{
OUTPIXEL(*pc);
if ((k % PS_LINE) == 0)
putc('\n', fp);
}
for (pc = get_GM(im)[j], ss = pc + im->w; pc < ss; pc++, k++)
{
OUTPIXEL(*pc);
if ((k % PS_LINE) == 0)
putc('\n', fp);
}
for (pc = get_BM(im)[j], ss = pc + im->w; pc < ss; pc++, k++)
{
OUTPIXEL(*pc);
if ((k % PS_LINE) == 0)
putc('\n', fp);
}
REPORT((im->h - 1 - j), rlines);
}
img_free_rgbmem(im);
putc('\n', im->fp);
PS_pop(im->fp);
return 0;
}
/************************************************************************
* GUI part of the PostScript support and ultimately we want
* paper size, x and/or y scale, placement and print resolution
**********************************************************************/
/* tem copies */
static float lpw = PG_WIDTH, lph = PG_HEIGHT;
static float lhm = MARGIN, lvm = MARGIN;
static float lxscale = 1.0, lyscale = 1.0;
static int lautoscale = 1, ltextscale, lmatchscreen;
static int lplace = -1;
static int cpaper, defp;
static int ldpi = PRINTER_DPI;
static void reset_form(void);
static FL_OBJECT *xshow, *yshow;
static FL_OBJECT *sum;
/***************************************************************
* Make a local copy of the control parameters for undo.
* Need to use the control parameters for interactive reporting
***************************************************************/
static void
copy_real(void)
{
lpw = page_w;
lph = page_h;
lxscale = gxscale;
lyscale = gyscale;
ldpi = pdpi;
lautoscale = autoscale;
ltextscale = textscale;
lmatchscreen = matchscreen;
lplace = place;
cpaper = defp - 1;
lhm = hm;
lvm = vm;
}
static void
cancel_change(void)
{
page_w = lpw;
page_h = lph;
gxscale = lxscale;
gyscale = lyscale;
autoscale = lautoscale;
textscale = ltextscale;
matchscreen = lmatchscreen;
place = lplace;
hm = lhm;
vm = lvm;
pdpi = ldpi;
defp = cpaper + 1;
}
/*** Summarize current settings and (possibly) results *****/
static void
get_summary(void)
{
int w = imgptr->w, h = imgptr->h;
float winch, hinch;
float pw = page_w - 2 * hm;
float ph = page_h - 2 * vm;
char tmp[80];
check_size(&w, &h, 0);
/* resulting hardcopy size in inches */
winch = (w + (miscl + miscr) * s2p * gxscale) / 72.0;
hinch = (h + (misct + miscb) * s2p * gyscale) / 72.0;
if (!landscape)
sprintf(tmp, "printed size %.2g X %.2g inch", winch, hinch);
else
sprintf(tmp, "printed size %.2g X %.2g inch", hinch, winch);
/* if too large, change size to red */
if ((landscape && (hinch > pw || winch > ph)) ||
(!landscape && (winch > pw || hinch > ph)))
fl_set_object_lcol(sum, FL_RED);
else
fl_set_object_lcol(sum, FL_BLACK);
fl_set_object_label(sum, tmp);
}
/********* cancel. copy the true one to local one *******/
/* ARGSUSED */
static void
ok_cancel(FL_OBJECT * p, long ok)
{
if (ok)
{
copy_real();
update_dumpinfo(PS_wdefault(0));
}
else
{
cancel_change();
reset_form();
}
bit_hide_form(fmpsinit);
fl_activate_all_forms();
}
/* handle xscale */
#define MINPSSCALE 0.05 /* minimum scale */
#define MAXPSSCALE 5.0 /* maximum scale */
#define MINPSSTEP 0.01 /* change rate */
#define MAXPSSTEP 0.10 /* change rate */
/* ARGSUSED */
static void
xscale_cb(FL_OBJECT * p, long q)
{
const char *rep;
if (autoscale)
return;
if (q == 4)
{ /* small decrease */
gxscale -= MINPSSTEP;
}
else if (q == 44)
{ /* large decrease */
gxscale -= MAXPSSTEP;
}
else if (q == 6)
{ /* small increase */
gxscale += MINPSSTEP;
}
else if (q == 66)
{ /* large increase */
gxscale += MAXPSSTEP;
}
if (gxscale < MINPSSCALE)
gxscale = MINPSSCALE;
if (gxscale > MAXPSSCALE)
gxscale = MAXPSSCALE;
gyscale = gxscale;
get_summary();
rep = ftoa(gxscale, 2);
fl_set_object_label(xshow, rep);
fl_set_object_label(yshow, rep);
}
/* ARGSUSED */
static void
yscale_cb(FL_OBJECT * p, long q)
{
if (q == 4)
{ /* small decrease */
gyscale -= MINPSSTEP;
}
else if (q == 44)
{ /* large decrease */
gyscale -= MAXPSSTEP;
}
else if (q == 6)
{ /* small increase */
gyscale += MINPSSTEP;
}
else if (q == 66)
{ /* large increase */
gyscale += MAXPSSTEP;
}
if (gyscale < MINPSSCALE)
gyscale = MINPSSCALE;
if (gyscale > MAXPSSCALE)
gyscale = MAXPSSCALE;
fl_set_object_label(yshow, ftoa(gyscale, 2));
get_summary();
}
/* ARGSUSED */
static void
placement_cb(FL_OBJECT * p, long q)
{
place = q;
get_summary();
}
/* ARGSUSED */
static void
autoscale_cb(FL_OBJECT * p, long q)
/* preferably, all scale changing actions be disabled */
{
if ((autoscale = fl_get_button(p)))
{
fl_set_object_lcol(xshow, FL_INACTIVE);
fl_set_object_lcol(yshow, FL_INACTIVE);
}
else
{
fl_set_object_lcol(xshow, 0);
fl_set_object_lcol(yshow, 0);
}
get_summary();
fl_set_object_label(xshow, ftoa(gxscale, 2));
fl_set_object_label(yshow, ftoa(gyscale, 2));
}
/* ARGSUSED */
static void
textscale_cb(FL_OBJECT * p, long q)
{
textscale = fl_get_button(p);
}
/* ARGSUSED */
static void
matchscreen_cb(FL_OBJECT * p, long q)
{
matchscreen = fl_get_button(p);
get_summary();
}
struct papers
{
const char *name;
float w, h, m;
};
static struct papers allpapers[] =
{
{"Letter (8.5X11.0in)", 8.5, 11.0, MARGIN}, /* A US letter */
{"Legal (8.5X14.0in)", 8.5, 14.0, MARGIN},
{"A4 (210X295mm)", 7.27, 11.61, MARGIN}, /* European */
{"B4 (257X364mm)", 10.1, 14.33, MARGIN}, /* Japanese */
{"B5 (18X20cm)", 7.283, 10.630, MARGIN},
{"B (11X17in)", 11.0, 17.0, MARGIN}, /* US tabloid */
{"Note (4X5in)", 4.0, 5.0, 0.2}
};
static void
set_paper(int n)
{
page_w = allpapers[n].w;
page_h = allpapers[n].h;
hm = vm = allpapers[n].m;
get_summary();
}
/* ARGSUSED */
static void
paper_size(FL_OBJECT * p, long q)
{
int i = fl_get_choice(p);
if (i <= 0)
return;
cpaper = i - 1;
set_paper(cpaper);
}
/* ARGSUSED */
static int alldpi[] =
{
75, 150, 300, 400, 600, 1200, 0
};
static void
printer_cb(FL_OBJECT * p, long q)
{
int i = fl_get_choice(p);
static int j = PRINTER_DPI;
char buf[30];
if (i <= 0)
return;
if (i == sizeof(alldpi) / sizeof(alldpi[0]))
{
getint("EnterDPI", &j, 35, 3600, 0);
sprintf(buf, "%d or other", j);
fl_replace_choice(p, i, buf);
alldpi[i - 1] = j;
}
pdpi = alldpi[i - 1];
get_summary();
}
static FL_OBJECT *as, *ts, *sc, *ms;
static void
reset_form(void)
{
fl_set_button(as, autoscale);
fl_set_button(ts, textscale);
fl_set_button(ms, matchscreen);
fl_set_choice(sc, defp);
get_summary();
}
static void
create_form_psinit(void)
{
struct papers *ps, *p = allpapers;
char cc[30];
FL_OBJECT *obj;
int i;
float x, y, dx, dy;
if (fmpsinit)
return;
fmpsinit = fl_bgn_form(FL_NO_BOX, 255.0, 275.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 255.0, 275.0, "");
obj = fl_add_box(FL_NO_BOX, 30.0, 245.0, 200.0, 20.0, "PostScript Options");
fl_set_object_lcol(obj, 4);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
obj = fl_add_button(FL_HB, 0.0, 0.0, 255.0, 275.0, "");
fl_set_call_back(obj, help_cb, HELP_PS);
/* current results */
sum = obj = fl_add_text(FL_NT, 40.0, 215.0, 180.0, 20.0, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_CENTER);
/* placement */
fl_bgn_group();
obj = fl_add_roundbutton(FL_RB, 10.0, 180.0, 30.0, 30.0, rplace[1]);
fl_set_object_lsize(obj, 10.0);
fl_set_button(obj, place == 0);
fl_set_call_back(obj, placement_cb, 0);
obj = fl_add_roundbutton(FL_RB, 90.0, 180.0, 30.0, 30.0, rplace[2]);
fl_set_object_lsize(obj, 10.0);
fl_set_button(obj, place == 1);
fl_set_call_back(obj, placement_cb, 1);
obj = fl_add_roundbutton(FL_RB, 180.0, 180.0, 30.0, 30.0, rplace[0]);
fl_set_object_lsize(obj, 10.0);
fl_set_button(obj, place == -1);
fl_set_call_back(obj, placement_cb, -1);
fl_end_group();
/* paper size */
sc = obj = fl_add_choice(FL_NC, 65.0, 130.0, 140.0, 25.0, "Paper");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_lcol(obj, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_choice_fontsize(obj, 10.0);
fl_clear_choice(obj);
for (ps = p + sizeof(allpapers) / sizeof(allpapers[0]); p < ps; p++)
{
fl_addto_choice(obj, p->name);
if (Abs(p->w - page_w) < 0.1 && Abs(p->h - page_h) < 0.1)
defp = p - allpapers + 1;
}
if (defp <= 0)
defp = 1;
cpaper = defp - 1;
set_paper(cpaper);
fl_set_choice(obj, defp);
fl_set_call_back(obj, paper_size, 0);
/* printer resolutions */
obj = fl_add_choice(FL_NC, 65.0, 155.0, 140.0, 25.0, "Printer");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_lcol(obj, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_choice_fontsize(obj, 10.0);
fl_clear_choice(obj);
for (i = 0; i < sizeof(alldpi) / sizeof(alldpi[0]); i++)
{
if (alldpi[i] == 0)
fl_addto_choice(obj, "Other");
else
{
sprintf(cc, "%d DPI", alldpi[i]);
fl_addto_choice(obj, cc);
}
if (alldpi[i] == pdpi)
fl_set_choice(obj, i + 1);
}
fl_set_call_back(obj, printer_cb, 0);
/* scales */
xshow = obj = fl_add_box(FL_FRAME_BOX, 115.0, 100.0,
40.0, 25.0, (char *) ftoa(gxscale, 2));
fl_set_object_lsize(obj, 10.0);
obj = fl_add_text(FL_NT, 10.0, 100.0, 55.0, 25.0, "xscale");
fl_set_object_lcol(obj, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_CENTER);
obj = fl_add_button(FL_TOUCH_BUTTON, 180.0, 100.0, 25.0, 25.0, "@>>");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, xscale_cb, 66);
obj = fl_add_button(FL_TOUCH_BUTTON, 65.0, 100.0, 25.0, 25.0, "@<<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, xscale_cb, 44);
obj = fl_add_button(FL_TOUCH_BUTTON, 155.0, 100.0, 25.0, 25.0, "@>");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, xscale_cb, 6);
obj = fl_add_button(FL_TOUCH_BUTTON, 90.0, 100.0, 25.0, 25.0, "@<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, xscale_cb, 4);
yshow = obj = fl_add_box(FL_FRAME_BOX, 115.0, 75.0,
40.0, 25.0, (char *) ftoa(gyscale, 2));
fl_set_object_lsize(obj, 10.0);
obj = fl_add_text(FL_NT, 10.0, 75.0, 55.0, 25.0, "yscale");
fl_set_object_lcol(obj, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_CENTER);
obj = fl_add_button(FL_TOUCH_BUTTON, 180.0, 75.0, 25.0, 25.0, "@>>");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, yscale_cb, 66);
obj = fl_add_button(FL_TOUCH_BUTTON, 155.0, 75.0, 25.0, 25.0, "@>");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, yscale_cb, 6);
obj = fl_add_button(FL_TOUCH_BUTTON, 90.0, 75.0, 25.0, 25.0, "@<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, yscale_cb, 4);
obj = fl_add_button(FL_TOUCH_BUTTON, 65.0, 75.0, 25.0, 25.0, "@<<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 1);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, yscale_cb, 44);
/* text, autoscale and match screen */
dx = dy = 28.0;
x = 10.0;
y = 40.0;
as = obj = fl_add_roundbutton(FL_PB, x, y, dx, dy, "autoscale");
fl_set_object_lsize(obj, 10.0);
fl_set_button(obj, autoscale);
fl_set_call_back(obj, autoscale_cb, 0);
autoscale_cb(obj, 0);
x += dx + 50;
ts = obj = fl_add_roundbutton(FL_PB, x, y, dx, dy, "textscale");
fl_set_object_lsize(obj, 10.0);
fl_set_button(obj, textscale);
fl_set_call_back(obj, textscale_cb, 0);
x += dx + 50;
ms = obj = fl_add_roundbutton(FL_PB, x, y, dx, dy, "scrnsize");
fl_set_object_lsize(obj, 10.0);
fl_set_button(obj, matchscreen);
fl_set_call_back(obj, matchscreen_cb, 0);
/* control */
obj = fl_add_button(FL_RETB, 150.0, 10.0, 75.0, 25.0, "OK");
fl_set_object_color(obj, 47, 2);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, ok_cancel, 1);
obj = fl_add_button(FL_NB, 70.0, 10.0, 75.0, 25.0, "Cancel");
fl_set_object_color(obj, 47, 3);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, ok_cancel, 0);
fl_end_form();
/* initilize GUI local paramters */
copy_real();
}
#endif /* !defined PS * */
/****************************************************************
* get the sizes of text and sgfs that are outside of the image
******************************************************************/
void
get_misc_size(IPTR im, int *top, int *left, int *bottom, int *right)
{
int l, ll, t, tt, r, rr, b, bb;
get_text_bounds(im, &t, &l, &b, &r);
get_sgf_bounds(im, &tt, &ll, &bb, &rr);
*top = Max(t, tt);
*left = Max(l, ll);
*bottom = Max(b, bb);
*right = Max(r, rr);
if (screen_dpi == 0)
screen_dpi = get_scr_dpi();
*top = (*top * 72.0 / screen_dpi);
*left = (*left * 72.0 / screen_dpi);
*bottom = (*bottom * 72.0 / screen_dpi);
*right = (*right * 72.0 / screen_dpi);
}